aboutsummaryrefslogtreecommitdiff
path: root/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-01-24 13:09:50 +0000
committerFuwn <[email protected]>2026-01-24 13:09:50 +0000
commit396acf3bbbe00a192cb0ea0a9ccf91b1d8d2850b (patch)
treeb9df4ca6a70db45cfffbae6fdd7252e20fb8e93c /src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
downloadumami-main.tar.xz
umami-main.zip
Initial commitHEADmain
Created from https://vercel.com/new
Diffstat (limited to 'src/app/(main)/websites/[websiteId]/events/EventProperties.tsx')
-rw-r--r--src/app/(main)/websites/[websiteId]/events/EventProperties.tsx127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
new file mode 100644
index 0000000..c3b1325
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
@@ -0,0 +1,127 @@
+import { Column, Grid, ListItem, Select } from '@umami/react-zen';
+import { useMemo, useState } from 'react';
+import { PieChart } from '@/components/charts/PieChart';
+import { LoadingPanel } from '@/components/common/LoadingPanel';
+import {
+ useEventDataPropertiesQuery,
+ useEventDataValuesQuery,
+ useMessages,
+} from '@/components/hooks';
+import { ListTable } from '@/components/metrics/ListTable';
+import { CHART_COLORS } from '@/lib/constants';
+
+export function EventProperties({ websiteId }: { websiteId: string }) {
+ const [propertyName, setPropertyName] = useState('');
+ const [eventName, setEventName] = useState('');
+
+ const { formatMessage, labels } = useMessages();
+ const { data, isLoading, isFetching, error } = useEventDataPropertiesQuery(websiteId);
+
+ const events: string[] = data
+ ? data.reduce((arr: string | any[], e: { eventName: any }) => {
+ return !arr.includes(e.eventName) ? arr.concat(e.eventName) : arr;
+ }, [])
+ : [];
+ const properties: string[] = eventName
+ ? data?.filter(e => e.eventName === eventName).map(e => e.propertyName)
+ : [];
+
+ return (
+ <LoadingPanel
+ data={data}
+ isLoading={isLoading}
+ isFetching={isFetching}
+ error={error}
+ minHeight="300px"
+ >
+ <Column gap="6">
+ {data && (
+ <Grid columns="repeat(auto-fill, minmax(300px, 1fr))" marginBottom="3" gap>
+ <Select
+ label={formatMessage(labels.event)}
+ value={eventName}
+ onChange={setEventName}
+ placeholder=""
+ >
+ {events?.map(p => (
+ <ListItem key={p} id={p}>
+ {p}
+ </ListItem>
+ ))}
+ </Select>
+ <Select
+ label={formatMessage(labels.property)}
+ value={propertyName}
+ onChange={setPropertyName}
+ isDisabled={!eventName}
+ placeholder=""
+ >
+ {properties?.map(p => (
+ <ListItem key={p} id={p}>
+ {p}
+ </ListItem>
+ ))}
+ </Select>
+ </Grid>
+ )}
+ {eventName && propertyName && (
+ <EventValues websiteId={websiteId} eventName={eventName} propertyName={propertyName} />
+ )}
+ </Column>
+ </LoadingPanel>
+ );
+}
+
+const EventValues = ({ websiteId, eventName, propertyName }) => {
+ const {
+ data: values,
+ isLoading,
+ isFetching,
+ error,
+ } = useEventDataValuesQuery(websiteId, eventName, propertyName);
+
+ const propertySum = useMemo(() => {
+ return values?.reduce((sum, { total }) => sum + total, 0) ?? 0;
+ }, [values]);
+
+ const chartData = useMemo(() => {
+ if (!propertyName || !values) return null;
+ return {
+ labels: values.map(({ value }) => value),
+ datasets: [
+ {
+ data: values.map(({ total }) => total),
+ backgroundColor: CHART_COLORS,
+ borderWidth: 0,
+ },
+ ],
+ };
+ }, [propertyName, values]);
+
+ const tableData = useMemo(() => {
+ if (!propertyName || !values || propertySum === 0) return [];
+ return values.map(({ value, total }) => ({
+ label: value,
+ count: total,
+ percent: 100 * (total / propertySum),
+ }));
+ }, [propertyName, values, propertySum]);
+
+ return (
+ <LoadingPanel
+ isLoading={isLoading}
+ isFetching={isFetching}
+ data={values}
+ error={error}
+ minHeight="300px"
+ gap="6"
+ >
+ {values && (
+ <Grid columns="1fr 1fr" gap>
+ <ListTable title={propertyName} data={tableData} />
+ <PieChart type="doughnut" chartData={chartData} />
+ </Grid>
+ )}
+ </LoadingPanel>
+ );
+};